

namespace Stee.CAP8.MessageBus.Sample
{
    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using Stee.CAP8.MessageBus.Interface.Enums;
    using Stee.CAP8.MessageBus.Interface.Interfaces;
    using Stee.CAP8.MessageBus.Interface.Models;
    using Stee.CAP8.MessageBus.Kafka.Configurations;
    using Stee.CAP8.MessageBus.Kafka.Publisher;
    using Stee.CAP8.MessageBus.Sample.Model;

    public class Program
    {
        #region Test Variables

        private static readonly string topic = "first_topic";
        private static readonly string key = "first_key";
        private static readonly string groupID = "second_group";
        private static readonly TopicName topicName = new TopicName(topic, key, MessageType.Event);

        private static readonly Dictionary<string, string> properties = new Dictionary<string, string>
        {
            { "test-header", "some-value" },
        };

        private static readonly Person p1 = new Person("QWERTY1", 21);
        private static readonly Person p2 = new Person("QWERTY2", 22);
        private static readonly Person p3 = new Person("QWERTY3", 23);
        private static readonly Person p4 = new Person("QWERTY4", 24);

        private static IPublisher<string> publisher;
        private static IPublisher<Person> publisherObject;
        private static ISubscriber<object> subscriber;

        #endregion Test Variables


        private static string consoleInputInstruction = "Enter a message: ";
        private static bool isExit = false;

        private static ManualResetEvent quitEvent = new ManualResetEvent(false);


        public static void Main(string[] args)
        {
            Task t = TestPublish();
            t.Wait();


            //// Press Ctrl + C to quit
            Console.CancelKeyPress += (sender, eArgs) =>
            {
                quitEvent.Set();
                eArgs.Cancel = true;
            };

            quitEvent.WaitOne();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private static async Task TestPublish()
        {
            try
            {
                PublisherConfiguration publishConfig = new PublisherConfiguration(new Dictionary<string, string>
                {
                    { "BootstrapServers", "127.0.0.1:9092" },
                    { "Acks", "All" },
                    { "ClientID", "mypublisher" },
                    { "EnableIdempotence", "true" },
                    { "LingerMs", "0.5" },
                    { "MessageSendMaxRetries", "2" },
                    { "MessageTimeoutMs", "300000" },
                    { "QueueBufferingMaxKbytes", "1048576" },
                    { "QueueBufferingMaxMessages", "100000" },
                });

                publisher = new PublisherImpl<string>(topicName, publishConfig, PublishResponseHandler);
                publisherObject = new PublisherImpl<Person>(topicName, publishConfig, PublishResponsePersonHandler);

                while (!isExit)
                {
                    //// Publish simple string
                    Console.Clear();
                    Console.Write(consoleInputInstruction);
                    string input = Console.ReadLine().Trim();

                    if (!string.IsNullOrEmpty(input))
                    {
                        publisher.Publish($"{input}", properties, CancellationToken.None);

                        if (input.Equals("Exit", StringComparison.InvariantCultureIgnoreCase))
                        {
                            isExit = true;
                        }
                    }


                    ////// Publish 1 w/o properties
                    //publisher.Publish($"Publish w/o properties - The date/time now is: {DateTime.Now}", CancellationToken.None);
                    //publisherObject.Publish(p1, CancellationToken.None);

                    ////// Publish 2 w/ properties
                    //publisher.Publish($"Publish w/ properties - The date/time now is: {DateTime.Now}", properties, CancellationToken.None);
                    //publisherObject.Publish(p2, properties, CancellationToken.None);

                    ////// Async publish 1 w/o properties
                    //await publisher.PublishAsync($"PublishAsync w/o properties - The date/time now is: {DateTime.Now}", CancellationToken.None).ConfigureAwait(false);
                    //await publisherObject.PublishAsync(p3, CancellationToken.None).ConfigureAwait(false);

                    ////// Async publish 2 w/ properties
                    //await publisher.PublishAsync(messageDTO4, properties, CancellationToken.None).ConfigureAwait(false);
                    //await publisherObject.PublishAsync(p4, properties, CancellationToken.None).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[ERROR] {ex.Message}");
                throw;
            }
            finally
            {
                publisher.Dispose();

                if (publisher.IsDisposed)
                {
                    Console.WriteLine($"Publisher is disposed.");
                }
                else
                {
                    Console.WriteLine($"[ERROR] Publisher is not disposed.");
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        private static bool PublishResponseHandler(PublishOutcome<string> response)
        {
            bool isHandled = false;

            if (response != null)
            {
                isHandled = true;
            }

            return isHandled;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        private static bool PublishResponsePersonHandler(PublishOutcome<Person> response)
        {
            bool isHandled = false;

            if (response != null)
            {
                isHandled = true;
            }

            return isHandled;
        }
    }
}
